package com.cougil.uoc.seghismed.business.impl;

import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.persistence.Query;

import com.cougil.uoc.seghismed.business.MetgeService;
import com.cougil.uoc.seghismed.business.VisitaService;
import com.cougil.uoc.seghismed.model.Visita;
import com.cougil.uoc.seghismed.model.ciphed.VisitaCiphed;

/**
 * Classe que implementa els mètodes vinculats amb la gestió de la informació relacionada amb les
 * Visites
 *
 * @author Ignacio Cougil Jares
 *
 */
public class VisitaServiceImpl extends CoreServerServiceImpl implements
VisitaService {

	private MetgeService metgeService;

	private void findAndRemoveVisitaCiphed(Visita visita) {
		CoreServerServiceImpl.logger.debug("Intentant esborrar la visita xifrada associat a la visita ["
				+ visita.getId() + "]");
		List<VisitaCiphed> visitesXifrades = this.findVisitesCiphed();
		VisitaCiphed vc = this.findVisitaCiphed(visitesXifrades, visita);
		if (vc != null) {
			// eliminem finalment la visita xifrada
			this.em.remove(vc);
			CoreServerServiceImpl.logger.debug("Visita xifrada associada a la visita [" + visita.getId()
					+ "] esborrada satisfactoriament");
		} else {
			CoreServerServiceImpl.logger.debug("Visita xifrada associada a la visita [" + visita.getId()
					+ "] no esborrada!");
		}
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.VisitaService#findById(java.lang.Integer)
	 */
	public Visita findById(Integer id) {
		Visita p = this.em.find(Visita.class, id);
		if (p != null) {
			CoreServerServiceImpl.logger.debug("Visita ["+p+"] trobada satisfactoriament");
		} else {
			CoreServerServiceImpl.logger.debug("Visita ["+id+"] no trobada!");
		}
		return p;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.VisitaService#findLastVisitaCiphed()
	 */
	@SuppressWarnings("unchecked")
	public VisitaCiphed findLastVisitaCiphed() {
		CoreServerServiceImpl.logger.debug("Intentant cercar l'última visita xifrada");
		VisitaCiphed vc = null;
		Query query = this.em
		.createQuery("SELECT vc FROM VisitaCiphed vc WHERE vc.id = (SELECT MAX(id) FROM VisitaCiphed)");
		List<VisitaCiphed> llista = query.getResultList();
		if (llista.size() > 0) {
			vc = llista.get(0);
			CoreServerServiceImpl.logger.debug("Visita xifrada [" + vc + "] trobada satisfactoriament");
		} else {
			CoreServerServiceImpl.logger.debug("Visita xifrada no trobada!");
		}
		return vc;
	}


	/*
	 * (non-Javadoc)
	 *
	 * @see com.cougil.uoc.seghismed.business.VisitaService#findVisitaCiphed(java.util.List,
	 * com.cougil.uoc.seghismed.model.Visita)
	 */
	public VisitaCiphed findVisitaCiphed(List<VisitaCiphed> visitesXifrades, Visita visita) {
		CoreServerServiceImpl.logger.debug("Intentant cercar la visita xifrada associada a la visita ["
				+ visita.getId() + "]");
		VisitaCiphed vc = null;
		boolean trobada = false;
		for (Iterator<VisitaCiphed> iterator = visitesXifrades.iterator(); iterator.hasNext()
		&& !trobada;) {
			vc = iterator.next();
			Visita vDesxifrada = this.cipherService.verificarDesxifrarVisita(vc, this.getGestor());
			trobada = vDesxifrada.getId().equals(visita.getId());
		}
		if (trobada) {
			CoreServerServiceImpl.logger.debug("Visita xifrada associada a la visita [" + visita.getId()
					+ "] trobada satisfactoriament");
		} else {
			CoreServerServiceImpl.logger.debug("Visita xifrada associada a la visita [" + visita.getId()
					+ "] no trobada!");
		}
		return vc;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see com.cougil.uoc.seghismed.business.VisitaService#findVisitaCiphed(java.util.Set,
	 * com.cougil.uoc.seghismed.model.Visita)
	 */
	@Override
	public VisitaCiphed findVisitaCiphed(Set<VisitaCiphed> visitesXifrades, Visita visita) {
		CoreServerServiceImpl.logger.debug("Intentant cercar la visita xifrada associada a la visita ["
				+ visita.getId() + "] dintre d'un conjunt de visites xifrades");
		VisitaCiphed vc = null;
		boolean trobada = false;
		for (Iterator<VisitaCiphed> iterator = visitesXifrades.iterator(); iterator.hasNext() && !trobada;) {
			vc = iterator.next();
			Visita vDesxifrada = this.cipherService.verificarDesxifrarVisita(vc, this.getGestor());
			trobada = vDesxifrada.getId().equals(visita.getId());
		}
		if (trobada) {
			CoreServerServiceImpl.logger.debug("Visita xifrada associada a la visita [" + visita.getId()
					+ "] trobada satisfactoriament");
		} else {
			CoreServerServiceImpl.logger.debug("Visita xifrada associada a la visita [" + visita.getId()
					+ "] no trobada!");
		}
		return vc;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * com.cougil.uoc.seghismed.business.VisitaService#findVisitaCiphed(com.cougil.uoc.seghismed
	 * .model.Visita)
	 */
	public VisitaCiphed findVisitaCiphed(Visita visita) {
		CoreServerServiceImpl.logger.debug("Intentant cercar la visita xifrada associada a la visita ["
				+ visita.getId() + "]");
		List<VisitaCiphed> visitesXifradess = this.findVisitesCiphed();
		return this.findVisitaCiphed(visitesXifradess, visita);
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.VisitaService#findAll()
	 */
	@SuppressWarnings("unchecked")
	public List<Visita> findVisites() {
		CoreServerServiceImpl.logger.debug("Intentant cercar totes les visites");
		Query query = this.em.createQuery("SELECT v FROM Visita v");
		List<Visita> llista = query.getResultList();
		CoreServerServiceImpl.logger.debug(llista.size()+" visites trobades satisfactoriament");
		return llista;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see com.cougil.uoc.seghismed.business.VisitaService#findVisitesCiphed()
	 */
	@SuppressWarnings("unchecked")
	public List<VisitaCiphed> findVisitesCiphed() {
		CoreServerServiceImpl.logger.debug("Intentant cercar totes les visites xifrades");
		Query query = this.em.createQuery("SELECT v FROM VisitaCiphed v");
		List<VisitaCiphed> llista = query.getResultList();
		CoreServerServiceImpl.logger.debug(llista.size() + " visites xifrades trobades satisfactoriament");
		return llista;
	}

	/**
	 * @return Retorna el valor de la propietat metgeService
	 */
	public MetgeService getMetgeService() {
		return this.metgeService;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.VisitaService#remove(java.lang.Integer)
	 */
	public void remove(Integer id) {
		CoreServerServiceImpl.logger.debug("Intentant esborrar la Visita amb id: "+id);
		Visita visita = this.findById(id);
		if (visita != null) {
			// veure métode PacientServiceImpl.findPacientCiphedByIdCiphed()
			/* 	Cal esborrar aquella visita xifrada que el seu ID coincideixi amb la que es preten esborrar.
			En realitat hauríem de fer servir els mètodes que venen a continuació, perqué aquest métode no és del tot
			eficient, donat que desxifra cadascun de les visites xifrades una per una fins que trobi una que el seu ID
			coincideixi amb l'ID de la visita */
			this.findAndRemoveVisitaCiphed(visita);

			// finalment eliminem la visita
			this.em.remove(visita);
			CoreServerServiceImpl.logger.debug("Visita ["+visita+"] esborrada satisfactoriament");
		} else {
			CoreServerServiceImpl.logger.debug("Visita ["+id+"] no esborrada!");
		}
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.VisitaService#remove(java.util.Set)
	 */
	@Override
	public void remove(Set<VisitaCiphed> visitesProtegides) {
		CoreServerServiceImpl.logger.debug("Intentant esborrar "+visitesProtegides.size()+" visites protegides");
		// desxifrem les visites, per tal d'anar-les eliminat una a una
		Set<Visita> visites = this.cipherService.verificarDesxifrarVisitesProtegides(visitesProtegides, this.getGestor());
		for (Visita visita : visites) {
			this.remove(visita.getId());
		}
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.VisitaService#removeAll()
	 */
	public int removeAll() {
		List<Visita> llista = this.findVisites();
		int i = 0;
		for (Iterator<Visita> iterator = llista.iterator(); iterator.hasNext();) {
			Visita visita = iterator.next();
			this.remove(visita.getId());
			i++;
		}
		CoreServerServiceImpl.logger.debug(i+" visites esborrades satisfactoriament");
		return i;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.VisitaService#save(com.cougil.uoc.seghismed.model.Visita)
	 */
	public void save(Visita visita) {
		CoreServerServiceImpl.logger.debug("Intentant emmagatzemar la Visita: "+visita);

		// nova visita
		if (visita.getId() == null) {
			if (visita.getDataAlta() == null) {
				visita.setDataAlta(new Date());
			}
			this.em.persist(visita);
			CoreServerServiceImpl.logger.debug("Visita ["+visita+"] emmagatzemada satisfactoriament");

			// cal instanciar un objecte VisitaCiphed que representa la visita xifrada només pel gestor
			VisitaCiphed vc = this.cipherService.signarXifrarVisita(visita, this.getGestor(), this.getGestor());
			this.save(vc);

			// la visita ja existeix, l'actualitzem
		} else {
			visita.setDataModificacio(new Date());
			this.em.merge(visita);
			CoreServerServiceImpl.logger.debug("Visita ["+visita+"] actualitzada satisfactoriament");
		}

	}

	private void save(VisitaCiphed vc) {
		CoreServerServiceImpl.logger.debug("Intentant emmagatzemar la visita xifrada: " + vc);
		if (vc.getId() == null) {
			this.em.persist(vc);
			CoreServerServiceImpl.logger.debug("Visita xifrada [" + vc + "] emmagatzemada satisfactoriament");

		} else {
			this.em.merge(vc);
			CoreServerServiceImpl.logger.debug("Visita xifrada [" + vc + "] actualitzada satisfactoriament");
		}
	}

	/**
	 * @param metgeService Estableix el valor de la propietat metgeService
	 */
	public void setMetgeService(MetgeService metgeService) {
		this.metgeService = metgeService;
	}

	/* (non-Javadoc)
	 * @see com.cougil.uoc.seghismed.business.VisitaService#totalVisites()
	 */
	@SuppressWarnings("unchecked")
	@Override
	public long totalVisites() {
		CoreServerServiceImpl.logger.debug("Intentant comptar totes les visites");
		Query query = this.em.createQuery("SELECT COUNT(*) FROM Visita");
		List<Long> llista = query.getResultList();
		long resultat = llista.get(0).longValue();
		CoreServerServiceImpl.logger.debug(resultat + " visites comptades");
		return resultat;
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see com.cougil.uoc.seghismed.business.VisitaService#totalVisitesCiphed()
	 */
	@SuppressWarnings("unchecked")
	@Override
	public long totalVisitesCiphed() {
		CoreServerServiceImpl.logger.debug("Intentant comptar totes les visites xifrades");
		Query query = this.em.createQuery("SELECT COUNT(*) FROM VisitaCiphed");
		List<Long> llista = query.getResultList();
		long resultat = llista.get(0).longValue();
		CoreServerServiceImpl.logger.debug(resultat + " visites xifrades comptades");
		return resultat;
	}



}
